Block programming languages such as C are often used for creating new software, since they support the development of flexible, user-defined functions or modules. Typically, related functions, each of which performs a single, well-defined task, are combined into a source file. These source files can be developed independently and subsequently linked with other files to create a single software program. Communication among different source files is facilitated through global variables and functions, which are accessible outside the source file in which they are defined.
By default, the scope of a variable or function object extends outside the source file in which it is defined. Objects that are accessed by a source file outside the source file in which they are defined must be identified as External (EXTERN) objects in the accessing files. This is accomplished by means of a declaration statement in the accessing file, which introduces the name of the EXTERN object into the accessing file so it can be included in the file's symbol table. In contrast, objects that are to be accessible only within the source file in which they are defined must be identified as Static (STATIC).
Declarations apply to data and function objects, typedefs, structs, enums, and unions. A definition on the other hand, is a declaration in which a data object has storage allocated or in which the code forming the body of a function is present. Definitions apply only to data and function objects, and will be EXTERN or STATIC in accordance with the scope of the object defined.
Proper declaration statements in an accessing file must accurately identify both the name of the object and its data type. The name of the object is entered into the symbol table of the accessing file, so the file can be properly compiled. However, it is easy to inadvertently write inaccurate declaration statements, since programs typically contain many separate files, and these are often developed independently by different programmers. Under these circumstances, the likelihood of mismatches between the name or data type of an object as it is defined and as it is declared is greatly increased. For example, a variable or function may be modified in the file in which it is defined without modifying the corresponding declaration statements in the accessing files. As a result, the symbol table of each accessing file will include an incorrect entry for the object, and an error at run time may result.
One approach to minimizing such mismatches is to create a second file for each source file, which contains a declaration statement for each object defined in the source file. The second file, referred to as an "include" file, can be added to each source file that references objects in the original file during the compile process. This approach maintains in a single location the names of all objects in a source file which are to be made accessible outside the file. However, the is object names and data types must still be updated manually, and the risk remains that a change in the definition of an object will not be reflected in the declaration of the object in the corresponding include file. Methods for automatically generating declarations from the external definitions of a source file have only been developed for certain types of function definitions.
Typedef, struct, enum, and union declarations present their own set of consistency problems. For example, typedef declarations define user-selected identifiers to represent one or more data type keywords in the C language, and these identifiers are then used as data types in definitions, declarations, and other typedef declarations. Conflicts may arise, however, when the same user-selected identifier is used in different source files to represent different C data types. In this case, the corresponding include files contain different declarations for the same user-defined identifier, and if these include files are added to a third source file to provide declarations for some other objects, the resulting conflict between typedef declarations will prevent the source file from compiling.
For this reason, many programming projects limit the use of include files and write declarations into the source file itself specifically to avoid such conflicts. However, this approach creates many copies of a declaration which are scattered throughout different source files, and enhances the possibility that one or more declarations will be inaccurate if the object definition changes.